package com.mrdeer.web.controller.sys;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mrdeer.common.JSONResult;
import com.mrdeer.common.constants.CommonConstant;
import com.mrdeer.common.entity.dto.UserDTO;
import com.mrdeer.common.entity.sys.*;
import com.mrdeer.common.exception.BusinessException;
import com.mrdeer.common.tools.RedisTemplateHelper;
import com.mrdeer.security.SecurityUserDetails;
import com.mrdeer.security.SecurityUtil;
import com.mrdeer.utils.AddMessage;
import com.mrdeer.utils.StopWordsUtil;
import com.mrdeer.web.service.sys.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@RestController
@Transactional
@CacheConfig(cacheNames = "user")
@Api(tags = "用户接口")
@RequestMapping("/mrdeer/user")
public class SysUserController {

    public static final String USER = "user::";

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysDepartmentService sysDepartmentService;

    @Resource
    private SysDepartmentHeaderService sysDepartmentHeaderService;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private AddMessage addMessage;

    @Resource
    private RedisTemplateHelper redisTemplate;

    @Resource
    private SecurityUtil securityUtil;

    @RequestMapping(value = "/smsLogin", method = RequestMethod.POST)
    @ApiOperation(value = "短信登录接口")
    public JSONResult smsLogin(@RequestParam String mobile, @RequestParam(required = false) Boolean saveLogin) {
        User u = sysUserService.findByMobile(mobile);
        if (u == null) {
            throw new BusinessException("手机号不存在");
        }
        String accessToken = securityUtil.getToken(u.getUsername(), saveLogin);
        //记录日志使用
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(new SecurityUserDetails(u), null, null);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return JSONResult.ok(accessToken);
    }

    @RequestMapping(value = "/resetByMobile", method = RequestMethod.POST)
    @ApiOperation(value = "通过短信重置密码")
    public JSONResult resetByMobile(@RequestParam String mobile, @RequestParam String password, @RequestParam String passStrength) {
        User u = sysUserService.findByMobile(mobile);
        String encryptPass = new BCryptPasswordEncoder().encode(password);
        u.setPassword(encryptPass).setPassStrength(passStrength);
        sysUserService.updateById(u);
        //删除缓存
        redisTemplate.delete(USER + u.getUsername());
        return JSONResult.ok("重置密码成功");
    }

    @RequestMapping(value = "/register", method = RequestMethod.POST)
    @ApiOperation(value = "注册用户")
    public JSONResult register(@Valid User u) {
        //校验是否已存在
        checkUserInfo(u.getUsername(), u.getMobile(), u.getEmail());
        String encryptPass = new BCryptPasswordEncoder().encode(u.getPassword());
        u.setPassword(encryptPass).setType(CommonConstant.USER_TYPE_NORMAL);
        sysUserService.save(u);
        User user = sysUserService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, u.getUsername()));
        //默认角色
        List<Role> roleList = null;
        if (roleList != null && roleList.size() > 0) {
            for (Role role : roleList) {
                UserRole ur = new UserRole().setUserId(user.getId()).setRoleId(role.getId());
                sysUserRoleService.save(ur);
            }
        }
        //异步发送创建账号消息
        addMessage.addSendMessage(user.getId());
        return JSONResult.ok(user);
    }

    @RequestMapping(value = "/info", method = RequestMethod.GET)
    @ApiOperation(value = "获取当前登录用户接口")
    public JSONResult getUserInfo() {
        User u = securityUtil.getCurrUser();
        //清除持久上下文环境，避免后面语句导致持久化
        u.setPassword(null);
        return JSONResult.ok(u);
    }

    @RequestMapping(value = "/changeMobile", method = RequestMethod.POST)
    @ApiOperation(value = "修改绑定手机")
    public JSONResult changeMobile(@RequestParam String mobile) {
        User user = securityUtil.getCurrUser();
        user.setMobile(mobile);
        sysUserService.updateById(user);
        //删除缓存
        redisTemplate.delete(USER + user.getUsername());
        return JSONResult.ok("修改手机号成功");
    }

    @RequestMapping(value = "/unlock", method = RequestMethod.POST)
    @ApiOperation(value = "解锁验证密码")
    public JSONResult unLock(@RequestParam String password) {
        User u = securityUtil.getCurrUser();
        if (!new BCryptPasswordEncoder().matches(password, u.getPassword())) {
            return JSONResult.errorMsg("密码不正确");
        }
        return JSONResult.ok(null);
    }

    @RequestMapping(value = "/resetPass", method = RequestMethod.POST)
    @ApiOperation(value = "重置密码")
    public JSONResult resetPass(@RequestParam String[] ids) {
        for (String id : ids) {
            User u = sysUserService.getById(id);
            //在线DEMO所需
            if ("test".equals(u.getUsername()) || "test2".equals(u.getUsername()) || "admin".equals(u.getUsername())) {
                throw new BusinessException("测试账号和管理员不得重置");
            }
            u.setPassword(new BCryptPasswordEncoder().encode("123456"));
            sysUserService.updateById(u);
            redisTemplate.delete(USER + u.getUsername());
        }
        return JSONResult.ok("操作成功");
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    @ApiOperation(value = "修改用户自己资料", notes = "用户名密码等不会修改 需要username更新缓存")
    @CacheEvict(key = "#u.username")
    public JSONResult editOwn(@RequestBody UserDTO u) {
        User old = securityUtil.getCurrUser();
        //不能修改的字段
        u.setUsername(old.getUsername()).setPassword(old.getPassword()).setType(old.getType()).setStatus(old.getStatus());
        sysUserService.updateById(u);
        return JSONResult.ok("修改成功");
    }

    @RequestMapping(value = "/modifyPass", method = RequestMethod.POST)
    @ApiOperation(value = "修改密码")
    public JSONResult modifyPass(@ApiParam("旧密码") @RequestParam String password,
                                 @ApiParam("新密码") @RequestParam String newPass,
                                 @ApiParam("密码强度") @RequestParam String passStrength) {
        User user = securityUtil.getCurrUser();
        //在线DEMO所需
        if ("test".equals(user.getUsername()) || "test2".equals(user.getUsername())) {
            return JSONResult.errorMsg("演示账号不支持修改密码");
        }
        if (!new BCryptPasswordEncoder().matches(password, user.getPassword())) {
            return JSONResult.errorMsg("旧密码不正确");
        }
        String newEncryptPass = new BCryptPasswordEncoder().encode(newPass);
        user.setPassword(newEncryptPass);
        user.setPassStrength(passStrength);
        sysUserService.updateById(user);
        //手动更新缓存
        redisTemplate.delete(USER + user.getUsername());
        return JSONResult.ok("修改密码成功");
    }

    @RequestMapping(value = "/getByCondition", method = RequestMethod.POST)
    @ApiOperation(value = "多条件分页获取用户列表")
    public JSONResult getByCondition(@RequestBody UserDTO user) {
        try {
            Page<User> page = sysUserService.list(user);
            if (null != page) {
                return JSONResult.ok(page);
            }
        } catch (Exception e) {
            return JSONResult.errorMsg(e.getMessage());
        }
        return JSONResult.errorMsg("");
    }

    @RequestMapping(value = "/getByDepartmentId/{departmentId}", method = RequestMethod.GET)
    @ApiOperation(value = "多条件分页获取用户列表")
    public JSONResult getByCondition(@PathVariable String departmentId) {
        List<User> list = sysUserService.list(new LambdaQueryWrapper<User>().eq(User::getDepartmentId, departmentId));
        list.forEach(u -> {
            u.setPassword(null);
        });
        return JSONResult.ok(list);
    }

    @RequestMapping(value = "/searchByName/{username}", method = RequestMethod.GET)
    @ApiOperation(value = "通过用户名搜索用户")
    public JSONResult searchByName(@PathVariable String username) throws UnsupportedEncodingException {
        List<User> list = sysUserService.list(new LambdaQueryWrapper<User>().eq(User::getUsername, URLDecoder.decode(username, "UTF-8")).eq(User::getStatus, CommonConstant.STATUS_NORMAL));
        list.forEach(u -> {
            u.setPassword(null);
        });
        return JSONResult.ok(list);
    }

    @RequestMapping(value = "/getAll", method = RequestMethod.GET)
    @ApiOperation(value = "获取全部用户数据")
    public JSONResult getAll() {
        List<User> list = sysUserService.list();
        //清除持久上下文环境 避免后面语句导致持久化
        for (User u : list) {
            u.setPassword(null);
        }
        return JSONResult.ok(list);
    }

    @RequestMapping(value = "/admin/add", method = RequestMethod.POST)
    @ApiOperation(value = "添加用户")
    public JSONResult add(@RequestBody User u, @RequestParam(required = false) String[] roleIds) {
        //校验是否已经存在
        checkUserInfo(u.getUsername(), u.getMobile(), u.getEmail());
        String encryptPass = new BCryptPasswordEncoder().encode(u.getPassword());
        u.setPassword(encryptPass);
        if (StrUtil.isNotBlank(u.getDepartmentId())) {
            Department d = sysDepartmentService.getById(u.getDepartmentId());
            if (d != null) {
                u.setDepartmentTitle(d.getTitle());
                u.setDepartmentId(d.getId());
            }
        } else {
            u.setDepartmentId(null);
            u.setDepartmentTitle("");
        }
        User add = sysUserService.add(u);
        if (roleIds != null) {
            //添加角色
            List<UserRole> userRoles = Arrays.asList(roleIds).stream().map(e -> {
                return new UserRole().setUserId(u.getId()).setRoleId(e);
            }).collect(Collectors.toList());
            sysUserRoleService.saveOrUpdateBatch(userRoles);
        }

        //发送创建账号消息
//        addMessage.addSendMessage(add.getId());

        return JSONResult.ok("添加成功");
    }

    @RequestMapping(value = "/admin/edit", method = RequestMethod.POST)
    @ApiOperation(value = "管理员资料", notes = "需要通过id获取原用户信息，需要username更新缓存")
    public JSONResult edit(@RequestBody UserDTO u) {
        User old = sysUserService.getById(u.getId());
        u.setUsername(old.getUsername());
        //若修改了手机和邮箱判断是否唯一
        if (!old.getMobile().equals(u.getMobile()) && sysUserService.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, u.getMobile())) != null) {
            return JSONResult.errorMsg("该手机号已绑定其它账号");
        }
        if (!old.getEmail().equals(u.getEmail()) && sysUserService.findByEmail(u.getEmail()) != null) {
            return JSONResult.errorMsg("该邮箱已绑定其它账号");
        }
        if (StrUtil.isNotBlank(u.getDepartmentId())) {
            Department d = sysDepartmentService.getById(u.getDepartmentId());
            if (d != null) {
                u.setDepartmentTitle(d.getTitle());
            }
        } else {
            u.setDepartmentId(null);
            u.setDepartmentTitle("");
        }
        u.setPassword(old.getPassword());
        sysUserService.updateById(u);
        //删除该用户角色
        sysUserRoleService.deleteByUserId(u.getId());
        if (u.getRoleIds() != null) {
            //新角色
            List<UserRole> userRoles = Arrays.asList(u.getRoleIds()).stream().map(e -> {
                return new UserRole().setRoleId(e).setUserId(u.getId());
            }).collect(Collectors.toList());
            sysUserRoleService.saveOrUpdateBatch(userRoles);
        }
        //手动删除缓存
        redisTemplate.delete("userRole::" + u.getId());
        redisTemplate.delete("userRole::depIds:" + u.getId());
        redisTemplate.delete("permission::userMenuList:" + u.getId());
        return JSONResult.ok("修改成功");
    }

    @RequestMapping(value = "/admin/disable/{userId}", method = RequestMethod.POST)
    @ApiOperation(value = "后台禁用用户")
    public JSONResult disable(@ApiParam("用户唯一ID标识") @PathVariable String userId) {
        User user = sysUserService.getById(userId);
        user.setStatus(CommonConstant.USER_STATUS_LOCK);
        sysUserService.updateById(user);
        //手动更新缓存
        redisTemplate.delete(USER + user.getUsername());
        return JSONResult.ok("操作成功");
    }

    @RequestMapping(value = "/admin/enable/{userId}", method = RequestMethod.POST)
    @ApiOperation(value = "后台启用用户")
    public JSONResult enable(@ApiParam("用户唯一id标识") @PathVariable String userId) {
        User user = sysUserService.getById(userId);
        user.setStatus(CommonConstant.USER_STATUS_NORMAL);
        sysUserService.updateById(user);
        //手动更新缓存
        redisTemplate.delete(USER + user.getUsername());
        return JSONResult.ok("操作成功");
    }

    @RequestMapping(value = "/delByIds", method = RequestMethod.POST)
    @ApiOperation(value = "批量通过ids删除")
    public JSONResult delAllByIds(@RequestParam String ids) {
        String[] idsArr = ids.split(",");
        for (String id : idsArr) {
            User u = sysUserService.getById(id);
            redisTemplate.delete(USER + u.getUsername());
            redisTemplate.delete("userRole::" + u.getId());
            redisTemplate.delete("userRole::depIds:" + u.getId());
            redisTemplate.delete("permission::userMenuList:" + u.getId());
            redisTemplate.deleteByPattern("department::*");

            sysUserService.delete(id);

            //删除关联角色
            sysUserRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, id));
            //删除关联部门负责人
            sysDepartmentHeaderService.remove(new LambdaQueryWrapper<DepartmentHeader>().eq(DepartmentHeader::getUserId, id));
            //删除关联流程、社交账号数据
            try {

            } catch (Exception e) {
                log.warn(e.getMessage());
            }
        }
        return JSONResult.ok("批量通过id删除数据成功");
    }

    @RequestMapping(value = "/importData", method = RequestMethod.POST)
    @ApiOperation(value = "导入用户数据")
    public JSONResult importData(@RequestBody List<User> users) {
        return JSONResult.ok(null);
    }

    /**
     * 校验
     *
     * @param username 用户名 不检验传空字符或null，下同
     * @param mobile   手机号
     * @param email    邮箱
     */
    public void checkUserInfo(String username, String mobile, String email) {
        //禁用词
        StopWordsUtil.matchWord(username);

        if (StrUtil.isNotBlank(username) && sysUserService.findByUsername(username) != null) {
            throw new BusinessException("该登录账号已被注册");
        }
        if (StrUtil.isNotBlank(email) && sysUserService.findByEmail(email) != null) {
            throw new BusinessException("该邮箱已被注册");
        }
        if (StrUtil.isNotBlank(mobile) && sysUserService.findByMobile(mobile) != null) {
            throw new BusinessException("该手机号已被注册");
        }
    }
}
